﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;

namespace VisualRibbonEditor
{
	//This file contails metadata of the ribbon xml schema for Actions, EnableRules, and DisplayRules elements.
	//This data is used by the ElementEditor control to determine which xml elements can be added as children
	//of other elements and what attributes are available on each element.

	public class ElementType
	{
		public string ElementName;
		public string[] ChildElements;
		public AttributeType[] Attributes;
		public string TextFormat;
		public string NewChildTooltip;
		public string Description;
	}

	public class AttributeType
	{
		public string AttributeName;
		public string[] OptionValues;
		public string[] OptionDisplayNames;
		public bool FreeText;
		public bool IsRequired;
	}

	public class Meta
	{
		static Dictionary<string, ElementType> _cachedTypes;

		private static List<ElementType> GetTypeInternal()
		{
			List<ElementType> list = new List<ElementType>();

			#region Actions

			list.Add(new ElementType()
			{
				ElementName = "Actions",
				TextFormat = "Action:",
				NewChildTooltip = "Add a new action",
				ChildElements = new string[] { "JavaScriptFunction", "Url" },
				Attributes = new AttributeType[0]
			});

			list.Add(new ElementType()
			{
				ElementName = "JavaScriptFunction",
				TextFormat = "JavaScript Function: {FunctionName}",
				NewChildTooltip = "Add a new parameter for this javascript function",
				Description = "An action that calls a function from a specific JScript library.",
				ChildElements = new string[] { "BoolParameter", "DecimalParameter", "CrmParameter", "IntParameter", "StringParameter" },
				Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "FunctionName", FreeText = true, IsRequired = true},
					new AttributeType(){ AttributeName = "Library", FreeText = true, IsRequired = true }
				}
			});

			list.Add(new ElementType()
			{
				ElementName = "Url",
				TextFormat = "Url: {Address}",
				NewChildTooltip = "Add a new parameter for this url",
				Description = "An action that opens a web page at a specified address. ",
				ChildElements = new string[] { "BoolParameter", "DecimalParameter", "CrmParameter", "IntParameter", "StringParameter" },
				Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Address", FreeText = true, IsRequired = true},
					new AttributeType(){ AttributeName = "PassParams", OptionValues = new string[] { "true", "false" }},
					new AttributeType()
					{
						AttributeName = "WinMode",
						OptionValues = new string[] { "0", "1", "2" },
						OptionDisplayNames = new string[] { "Window", "Modal Dialog", "Modeless Dialog" }
					},
					new AttributeType(){ AttributeName = "WinParams", FreeText = true}
				}
			});

			list.Add(new ElementType()
			{
				ElementName = "BoolParameter",
				TextFormat = "Boolean Parameter: {Value}",
				Description = "Specifies a value with a boolean data type that may be passed as a parameter. ",
				ChildElements = new string[0],
				Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Value", IsRequired = true, OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "Name", FreeText = true}
				}
			});

			list.Add(new ElementType()
			{
				ElementName = "DecimalParameter",
				TextFormat = "Decimal Parameter: {Value}",
				Description = "Specifies a value with a decimal data type that may be passed as a parameter. ",
				ChildElements = new string[0],
				Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Value", FreeText = true, IsRequired = true},
					new AttributeType(){ AttributeName = "Name", FreeText = true}
				}
			});

			list.Add(new ElementType()
			{
				ElementName = "IntParameter",
				TextFormat = "Integer Parameter: {Value}",
				Description = "Specifies a value with an integer data type that may be passed as a parameter. ",
				ChildElements = new string[0],
				Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Value", FreeText = true, IsRequired = true},
					new AttributeType(){ AttributeName = "Name", FreeText = true}
				}
			});

			list.Add(new ElementType()
			{
				ElementName = "StringParameter",
				TextFormat = "String Parameter: {Value}",
				Description = "Specifies a value with a string data type that may be passed as a parameter. ",
				ChildElements = new string[0],
				Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Value", FreeText = true, IsRequired = false},
					new AttributeType(){ AttributeName = "Name", FreeText = true}
				}
			});

			list.Add(new ElementType()
			{
				ElementName = "CrmParameter",
				TextFormat = "Crm Parameter: {Value}",
				Description = "Represents data retrieved from the CRM application that may be passed as a parameter. ",
				ChildElements = new string[0],
				Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Name", FreeText = true},
					new AttributeType(){ AttributeName = "Value",
						OptionValues = new string[]
						{
							"CommandProperties",
							"PrimaryEntityTypeCode",
							"PrimaryEntityTypeName",
							"PrimaryItemIds",
							"FirstPrimaryItemId",
							"PrimaryControl",
							"PrimaryControlId",
							"SelectedEntityTypeCode",
							"SelectedEntityTypeName",
							"FirstSelectedItemId",
							"SelectedControl",
							"SelectedControlSelectedItemCount",
							"SelectedControlSelectedItemIds",
							"SelectedControlSelectedItemReferences",
							"SelectedControlAllItemCount",
							"SelectedControlAllItemIds",
							"SelectedControlAllItemReferences",
							"SelectedControlUnselectedItemCount",
							"SelectedControlUnselectedItemIds",
							"SelectedControlUnselectedItemReferences",
							"OrgName",
							"OrgLcid",
							"UserLcid"
						}
					}
				}
			});

			#endregion


			list.Add(new ElementType()
			{
				ElementName = "EnableRules",
				TextFormat = "Enable Rules:",
				ChildElements = new string[] { "EnableRule" },
				NewChildTooltip = "Enable Rule"
			});


			list.Add(new ElementType()
			{
				ElementName = "EnableRule",
				NewChildTooltip = "Add a new Enable Rule",
				ChildElements = new string[] {
					"CrmClientTypeRule",
					"CrmOfflineAccessStateRule",
					"CrmOutlookClientTypeRule",
					"CustomRule",
					"EntityRule",
					"FormStateRule",
					"OrRule",
					"OutlookItemTrackingRule",
					"OutlookVersionRule",
					"PageRule",
					"RecordPrivilegeRule",
					"SelectionCountRule",
					"SkuRule",
					"ValueRule" },
				Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Id", FreeText = true}
				}
			});

			list.Add(new ElementType()
			{
				ElementName = "DisplayRules",
				TextFormat = "Display Rules:",
				ChildElements = new string[] { "DisplayRule" },
				NewChildTooltip = "Display Rule"
			});

			list.Add(new ElementType()
			{
				ElementName = "DisplayRule",
				NewChildTooltip = "Add a new Display Rule",
				ChildElements = new string[] {
					"CrmClientTypeRule",
					"CrmOfflineAccessStateRule",
					"CrmOutlookClientTypeRule",
					"CrmOutlookClientVersionRule",
					"EntityPrivilegeRule",
					"EntityPropertyRule",
					"EntityRule",
					"FormEntityContextRule",
					"FormStateRule",
					"MiscellaneousPrivilegeRule",
					"OrganizationSettingRule",
					"OrRule",
					"OutlookRenderTypeRule",
					"OutlookVersionRule",
					"PageRule",
					"ReferencingAttributeRequiredRule",
					"RelationshipTypeRule",
					"SkuRule",
					"ValueRule" },
				Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Id", FreeText = true}
				}
			});

			list.Add(new ElementType()
			{
				ElementName = "CrmClientTypeRule",
				TextFormat = "Client Type {=} {Type}",
				Description = "A rule that detects the type of CRM client. ",
				Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Type", IsRequired = true, OptionValues = new string[] { "Web", "Outlook" }},
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
			});

			list.Add(new ElementType()
			{
				ElementName = "CrmOfflineAccessStateRule",
				TextFormat = "Offline State {=} {State}",
				Description = "A rule that can be used to detect whether the Outlook client is currently operating Offline.",
				Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "State", IsRequired = true, OptionValues = new string[] { "Online", "Offline" }},
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
			});

			list.Add(new ElementType()
			{
				ElementName = "EntityPrivilegeRule",
				Description = "A rule that can detect the current user's privileges for a specific entity. ",
				TextFormat = "Entity {EntityName} Privilege {=} {PrivilegeType} {PrivilegeDepth}",
				Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "EntityName", FreeText = true},
					new AttributeType(){ AttributeName = "AppliesTo", OptionValues = new string[] { "PrimaryEntity", "SelectedEntity" }},
					new AttributeType(){ AttributeName = "PrivilegeDepth", IsRequired = true, OptionValues = new string[] { "None", "Basic", "Local", "Deep", "Global" }},
					new AttributeType(){ AttributeName = "PrivilegeType", IsRequired = true, OptionValues = new string[] { "Create", "Read", "Write", "Delete", "Assign", "Share", "Append", "AppendTo" }},
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
			});

			list.Add(new ElementType()
			{
				ElementName = "EntityPropertyRule",
				TextFormat = "Entity {EntityName} {has} {PropertyName}",
				Description = "A rule that can detect specific boolean properties of a CRM entity. ",
				Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "EntityName", FreeText = true},
					new AttributeType(){ AttributeName = "AppliesTo", OptionValues = new string[] { "PrimaryEntity", "SelectedEntity" }},
					new AttributeType(){ AttributeName = "PropertyName", IsRequired = true,
						OptionValues = new string[] {
							"DuplicateDetectionEnabled",
							"GridFiltersEnabled",
							"HasStateCode",
							"IsConnectionsEnabled",
							"MailMergeEnabled",
							"WorksWithQueue",
							"HasActivities",
							"IsActivity",
							"HasNotes",
							"IsCustomizable" }} ,
					new AttributeType(){ AttributeName = "PropertyValue", IsRequired = true, OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }},

				}
			});

			list.Add(new ElementType()
			{
				ElementName = "EntityRule",
				TextFormat = "Entity {EntityName} context {=} {Context}",
				Description = "A rule that can detect whether a specific entity is in context. ",
				Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "EntityName", FreeText = true, IsRequired = true},
					new AttributeType(){ AttributeName = "AppliesTo", OptionValues = new string[] { "PrimaryEntity", "SelectedEntity" }},
					new AttributeType(){ AttributeName = "Context", IsRequired = true, OptionValues = new string[] { "Form", "HomePageGrid", "SubGridStandard", "SubGridAssociated" }},
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
			});

			list.Add(new ElementType()
			{
				ElementName = "FormEntityContextRule",
				TextFormat = "Entity {=} {EntityName}",
				Description = "A rule that can detect whether a form ribbon is displayed in the context of a specific entity. ",
				Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "EntityName", FreeText = true, IsRequired = true},
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
			});

			list.Add(new ElementType()
			{
				ElementName = "FormStateRule",
				TextFormat = "Form State {=} {State}",
				Description = "A rule that can detect the state of the form. ",
				Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "State", IsRequired = true, OptionValues = new string[] { "Create", "Existing", "ReadOnly", "Disabled", "BulkEdit" }},
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
			});

			list.Add(new ElementType()
			{
				ElementName = "MiscellaneousPrivilegeRule",
				TextFormat = "User {has} privilege {PrivilegeName} {PrivilegeDepth}",
				Description = "A rule that can detect whether the user possesses a specific CRM privilege. ",
				Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "PrivilegeName", IsRequired = true, FreeText = true },
					new AttributeType(){ AttributeName = "PrivilegeDepth", IsRequired = true, OptionValues = new string[] { "Basic", "Local", "Deep", "Global" }},
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
			});

			list.Add(new ElementType()
			{
				ElementName = "OrganizationSettingRule",
				TextFormat = "Organization {has} setting {Setting}",
				Description = "A rule that can detect specific organization settings such as SharePoint integration being enabled or if the Fiscal Calendar is defined.",
				Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Setting", IsRequired = true, OptionValues = new string[] { "IsSharepointEnabled", "IsSOPIntegrationEnabled", "IsFiscalCalendarDefined" }},
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
			});

			list.Add(new ElementType()
			{
				ElementName = "OrRule",
				TextFormat = "OR:",
				Description = "A rule that contains a collection of rules so that this rule will evaluate as true if any of the rules in the collection evaluates as true. ",
				NewChildTooltip = "Add a new rule under this OrRule",
				ChildElements = new string[] { "Or" }
			});

			list.Add(new ElementType()
			{
				ElementName = "Or",
				TextFormat = "OR {...}",
				NewChildTooltip = "Add a new rule under this OrRule",
				ChildElements = new string[] {
					"CrmClientTypeRule",
					"CrmOfflineAccessStateRule",
					"CrmOutlookClientTypeRule",
					"CrmOutlookClientVersionRule",
					"CustomRule", // TODO: Only when descendant of <EnableRule>
					"EntityPrivilegeRule", // TODO: Only when descendant of <DisplayRule>
					"EntityPropertyRule", // TODO: Only when descendant of <DisplayRule>
					"EntityRule",
					"FormEntityContextRule", // TODO: Only when descendant of <DisplayRule>
					"FormStateRule",
					"MiscellaneousPrivilegeRule", // TODO: Only when descendant of <DisplayRule>
					"OrganizationSettingRule", // TODO: Only when descendant of <DisplayRule>
					"OutlookRenderTypeRule", // TODO: Only when descendant of <DisplayRule>
					"OutlookItemTrackingRule", // TODO: Only when descendant of <EnableRule>
					"OutlookVersionRule",
					"PageRule",
					"RecordPrivilegeRule",  // TODO: Only when descendant of <EnableRule>
					"ReferencingAttributeRequiredRule", // TODO: Only when descendant of <DisplayRule>
					"RelationshipTypeRule", // TODO: Only when descendant of <DisplayRule>
					"SelectionCountRule",  // TODO: Only when descendant of <EnableRule>
					"SkuRule",
					"ValueRule" }
			});


			list.Add(new ElementType()
			{
				ElementName = "OutlookRenderTypeRule",
				TextFormat = "Outlook render type {=} {Type}",
				Description = "A rule that can detect whether a form or list item is rendered as a web page or natively in Outlook.",
				Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Type", IsRequired = true, OptionValues = new string[] { "Web", "Outlook" }},
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
			});

			list.Add(new ElementType()
			{
				ElementName = "OutlookVersionRule",
				TextFormat = "Outlook version {=} {Version}",
				Description = "A rule that detects the version of Microsoft Office Outlook client. ",
				Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Version", IsRequired = true, OptionValues = new string[] { "2003", "2007", "2010" }},
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
			});


			list.Add(new ElementType()
			{
				ElementName = "PageRule",
				TextFormat = "Page address {=} {Address}",
				Description = "A rule that evaluates the address of the current page. ",
				Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Address", IsRequired = true, FreeText = true},
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
			});

			list.Add(new ElementType()
			{
				ElementName = "ReferencingAttributeRequiredRule",
				TextFormat = "Referencing attribute required level {=} 'required'",
				Description = "A rule that detects whether the referencing attribute for an entity is required.  ",
				Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
			});

			list.Add(new ElementType()
			{
				ElementName = "RelationshipTypeRule",
				TextFormat = "Relationship type {=} {RelationshipType}",
				Description = "A rule that detects whether a specific type of relationship exists between two entities. ",
				Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "AppliesTo", OptionValues = new string[] { "SelectedEntity" }},
					new AttributeType(){ AttributeName = "RelationshipType", IsRequired = true, OptionValues = new string[] { "OneToMany", "ManyToMany", "NoRelationship" }},
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
			});

			list.Add(new ElementType()
			{
				ElementName = "SkuRule",
				TextFormat = "CRM SKU {=} {Sku}",
				Description = "A rule that detects the Microsoft Dynamics CRM edition (e.g., Online or On-Premise).",
				Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Sku", IsRequired = true, OptionValues = new string[] { "OnPremise", "Online", "Spla" }},
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
			});

			list.Add(new ElementType()
			{
				ElementName = "ValueRule",
				TextFormat = "Field {Field} {=} {Value}",
				Description = "A rule that detects the value of a specific field on the current record.",
				Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Field", IsRequired = true, FreeText = true},
					new AttributeType(){ AttributeName = "Value", IsRequired = true, FreeText = true},
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
			});


			list.Add(new ElementType()
			{
				ElementName = "CrmOutlookClientTypeRule",
				TextFormat = "Outlook client type {=} {Type}",
				Description = "A rule that detects the type of CRM Outlook client (Crm for Outlook or CRM for Outlook with offline access).",
				Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Type", IsRequired = true, OptionValues = new string[] { "CrmForOutlook", "CrmForOutlookOfflineAccess" }},
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
			});

			list.Add(new ElementType()
			{
				ElementName = "CrmOutlookClientVersionRule",
				TextFormat = "Outlook Client version {=} {Major}.{Minor}.{Build}.{Revision}",
				Description = "A rule that detects the version of Microsoft Dynamics CRM for Microsoft Office Outlook. ",
				Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Major", IsRequired = true, FreeText = true},
					new AttributeType(){ AttributeName = "Minor", IsRequired = false, FreeText = true },
					new AttributeType(){ AttributeName = "Build", IsRequired = false, FreeText = true },
					new AttributeType(){ AttributeName = "Revision", IsRequired = false, FreeText = true },
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
			});

			list.Add(new ElementType()
			{
				ElementName = "CustomRule",
				TextFormat = "JavaScript Function: {FunctionName}",
				Description = "A rule that calls a function within a JScript library. ",
				NewChildTooltip = "Add a new parameter for this function",
				ChildElements = new string[] { "BoolParameter", "DecimalParameter", "CrmParameter", "IntParameter", "StringParameter" },
				Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Library", IsRequired = true, FreeText = true },
					new AttributeType(){ AttributeName = "FunctionName", IsRequired = true, FreeText = true },
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }},
				}
			});

			list.Add(new ElementType()
			{
				ElementName = "OutlookItemTrackingRule",
				TextFormat = "Outlook item {has} 'tracked in crm' = {TrackedInCrm}",
				Description = "A rule that detects whether the current outlook item is enabled for tracking in CRM.",
				Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "AppliesTo", OptionValues = new string[] { "PrimaryEntity" }},
					new AttributeType(){ AttributeName = "TrackedInCrm", IsRequired = true, OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
			});


			list.Add(new ElementType()
			{
				ElementName = "RecordPrivilegeRule",
				TextFormat = "User {has} privilege {PrivilegeType} on current record.",
				Description = "A rule that detects a user’s privileges for the current record. ",
				Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "AppliesTo", OptionValues = new string[] { "PrimaryEntity"  }},
					new AttributeType(){ AttributeName = "PrivilegeType", OptionValues = new string[] { "Create", "Read", "Write", "Delete", "Assign", "Share", "Append", "AppendTo" }},
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}

				}
			});

			list.Add(new ElementType()
			{
				ElementName = "SelectionCountRule",
				TextFormat = "Number of records selected {is} >= {Minimum} and <= {Maximum}",
				Description = "A rule that detects how many items in a grid are selected. ",
				Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "AppliesTo", OptionValues = new string[] { "PrimaryEntity", "SelectedEntity"  }},
					new AttributeType(){ AttributeName = "Maximum", FreeText = true },
					new AttributeType(){ AttributeName = "Minimum", FreeText = true },
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
			});

			return list;
		}

		public static Dictionary<string, ElementType> GetElementTypes()
		{
			if (_cachedTypes != null)
			{
				return _cachedTypes;
			}

			List<ElementType> list = GetTypeInternal();

			Dictionary<string, ElementType> dict = new Dictionary<string, ElementType>();
			foreach (ElementType t in list)
			{
				dict.Add(t.ElementName, t);
			}

			_cachedTypes = dict;

			return dict;

		}
		public static void SwitchToVersion5()
		{
			// Support for version 5.x Metadata elements

			// CommandClientTypeRule
			#region CommandClientTypeRule
			RemoveChildElement("EnableRule", "CommandClientTypeRule");
			RemoveChildElement("DisplayRule", "CommandClientTypeRule");
			RemoveChildElement("Or", "CommandClientTypeRule"); // TODO: Separate Display and Enable Or Rules
			RemoveElement("CommandClientTypeRule");
			#endregion CommandClientTypeRule

			// FormTypeRule
			#region FormTypeRule
			RemoveChildElement("DisplayRule", "FormTypeRule");
			RemoveChildElement("Or", "FormTypeRule"); // TODO: Separate Display and Enable Or Rules
			RemoveElement("FormTypeRule");
			#endregion FormTypeRule

			// HideForTabletExperienceRule
			#region HideForTabletExperienceRule
			RemoveChildElement("DisplayRule", "HideForTabletExperienceRule");
			RemoveChildElement("Or", "HideForTabletExperienceRule"); // TODO: Separate Display and Enable Or Rules
			RemoveElement("HideForTabletExperienceRule");
			#endregion HideForTabletExperienceRule

			// HideIfNetBreezeNotAvailableRule
			#region HideIfNetBreezeNotAvailableRule
			RemoveElement("HideIfNetBreezeNotAvailableRule");
			#endregion HideIfNetBreezeNotAvailableRule

			// HideIfServiceMetadataAvailableRule
			#region HideIfServiceMetadataAvailableRule
			RemoveElement("HideIfServiceMetadataAvailableRule");
			#endregion HideIfServiceMetadataAvailableRule

			// HideIfSharepointS2SConfigurationEnabledRule
			#region HideIfSharepointS2SConfigurationEnabledRule
			RemoveElement("HideIfSharepointS2SConfigurationEnabledRule");
			#endregion HideIfSharepointS2SConfigurationEnabledRule

			// HideIfExportToExcelNotEnabledRule
			#region HideIfExportToExcelNotEnabledRule
			RemoveChildElement("DisplayRule", "HideIfExportToExcelNotEnabledRule");
			RemoveChildElement("Or", "HideIfExportToExcelNotEnabledRule"); // TODO: Separate Display and Enable Or Rules
			RemoveElement("HideIfExportToExcelNotEnabledRule");
			#endregion HideIfExportToExcelNotEnabledRule

			// IsExportToExcelOnlineEnabledRule
			#region IsExportToExcelOnlineEnabledRule
			RemoveElement("IsExportToExcelOnlineEnabledRule");
			#endregion IsExportToExcelOnlineEnabledRule

			// HideIfDisabledForMobileRule
			#region HideIfDisabledForMobileRule
			RemoveElement("HideIfDisabledForMobileRule");
			#endregion HideIfDisabledForMobileRule

			// HideIfHybridSSSNotEnabledRule
			#region HideIfHybridSSSNotEnabledRule
			RemoveElement("HideIfHybridSSSNotEnabledRule");
			#endregion HideIfHybridSSSNotEnabledRule

			// HideIfDelveNotAvailableRule
			#region HideIfDelveNotAvailableRule
			RemoveElement("HideIfDelveNotAvailableRule");
			#endregion HideIfDelveNotAvailableRule

			// HideIfTestExchangeServerNotEnabledRule
			#region HideIfTestExchangeServerNotEnabledRule
			RemoveElement("HideIfTestExchangeServerNotEnabledRule");
			#endregion HideIfTestExchangeServerNotEnabledRule

			// HideIfSSSTroubleshootingNotEnabledRule
			#region HideIfSSSTroubleshootingNotEnabledRule
			RemoveElement("HideIfSSSTroubleshootingNotEnabledRule");
			#endregion HideIfSSSTroubleshootingNotEnabledRule

			// HideIfSSSTroubleshootingNotEnabledRule
			#region HideIfSSSTroubleshootingNotEnabledRule
			RemoveElement("HideIfSSSTroubleshootingNotEnabledRule");
			#endregion HideIfSSSTroubleshootingNotEnabledRule

			// HideIfCurrentUserIsNotSystemAdministratorRule
			#region HideIfCurrentUserIsNotSystemAdministratorRule
			RemoveElement("HideIfCurrentUserIsNotSystemAdministratorRule");
			#endregion HideIfCurrentUserIsNotSystemAdministratorRule

			// FeatureControlRule
			#region FeatureControlRule
			RemoveElement("FeatureControlRule");
			#endregion FeatureControlRule

			// HideIfEmailSignatureNotEnabledRule
			#region HideIfEmailSignatureNotEnabledRule
			RemoveElement("HideIfEmailSignatureNotEnabledRule");
			#endregion HideIfEmailSignatureNotEnabledRule

			// EntityPropertyRule - IsBusinessProcessEnabled
			#region EntityPropertyRule - IsBusinessProcessEnabled
			RemoveOptionValue("EntityPropertyRule", "PropertyName", "IsBusinessProcessEnabled");
			#endregion EntityPropertyRule - IsBusinessProcessEnabled

			// DeviceTypeRule
			#region DeviceTypeRule
			RemoveElement("DeviceTypeRule");
			#endregion DeviceTypeRule
		}
		public static void SwitchToVersion6()
		{
			SwitchToVersion5();

			// Support for version 6.x Metadata elements

			// CommandClientTypeRule
			#region CommandClientTypeRule
			if (!_cachedTypes.ContainsKey("CommandClientTypeRule"))
			{
				_cachedTypes.Add("CommandClientTypeRule", new ElementType()
				{
					ElementName = "CommandClientTypeRule",
					TextFormat = "Presentation Type {=} {Type}",
					Description = "A rule that detects the type of presentation being used. ",
					Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Type", IsRequired = true, OptionValues = new string[] { "Modern", "Refresh", "Legacy" }},
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
				});
			}
			AddChildElement("EnableRule", "CommandClientTypeRule");
			AddChildElement("DisplayRule", "CommandClientTypeRule");
			AddChildElement("Or", "CommandClientTypeRule"); // TODO: Separate Display and Enable Or Rules
			#endregion CommandClientTypeRule

			// FormTypeRule
			#region FormTypeRule
			if (!_cachedTypes.ContainsKey("FormTypeRule"))
			{
				_cachedTypes.Add("FormTypeRule", new ElementType()
				{
					ElementName = "FormTypeRule",
					TextFormat = "Form Type {=} {Type}",
					Description = "A rule that detects the type of Microsoft Dynamics CRM form. ",
					Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Type", IsRequired = true, OptionValues = new string[] { "Main", "Preview", "AppointmentBook", "Dashboard", "Quick", "QuickCreate" }},
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
				});
			}
			AddChildElement("DisplayRule", "FormTypeRule");
			AddChildElement("Or", "FormTypeRule"); // TODO: Separate Display and Enable Or Rules
			#endregion FormTypeRule

			// HideForTabletExperienceRule
			#region HideForTabletExperienceRule
			if (!_cachedTypes.ContainsKey("HideForTabletExperienceRule"))
			{
				_cachedTypes.Add("HideForTabletExperienceRule", new ElementType()
				{
					ElementName = "HideForTabletExperienceRule",
					TextFormat = "Hide For Tablet",
					Description = "A rule that will return false when the web application is viewed in a mobile browser on a tablet device. ",
					Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
				});
			}
			AddChildElement("DisplayRule", "HideForTabletExperienceRule");
			AddChildElement("Or", "HideForTabletExperienceRule"); // TODO: Separate Display and Enable Or Rules
			#endregion HideForTabletExperienceRule

			// HideIfNetBreezeNotAvailableRule
			#region HideIfNetBreezeNotAvailableRule
			if (!_cachedTypes.ContainsKey("HideIfNetBreezeNotAvailableRule"))
			{
				_cachedTypes.Add("HideIfNetBreezeNotAvailableRule", new ElementType()
				{
					ElementName = "HideIfNetBreezeNotAvailableRule",
					TextFormat = "HideIfNetBreezeNotAvailableRule",
					Description = "For internal use only",
					Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
				});
			}
			#endregion HideIfNetBreezeNotAvailableRule

			// HideIfServiceMetadataAvailableRule
			#region HideIfServiceMetadataAvailableRule
			if (!_cachedTypes.ContainsKey("HideIfServiceMetadataAvailableRule"))
			{
				_cachedTypes.Add("HideIfServiceMetadataAvailableRule", new ElementType()
				{
					ElementName = "HideIfServiceMetadataAvailableRule",
					TextFormat = "HideIfServiceMetadataAvailableRule",
					Description = "For internal use only",
					Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
				});
			}
			#endregion HideIfServiceMetadataAvailableRule

			// HideIfSharepointS2SConfigurationEnabledRule
			#region HideIfSharepointS2SConfigurationEnabledRule
			if (!_cachedTypes.ContainsKey("HideIfSharepointS2SConfigurationEnabledRule"))
			{
				_cachedTypes.Add("HideIfSharepointS2SConfigurationEnabledRule", new ElementType()
				{
					ElementName = "HideIfSharepointS2SConfigurationEnabledRule",
					TextFormat = "HideIfSharepointS2SConfigurationEnabledRule",
					Description = "For internal use only",
					Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
				});
			}
			#endregion HideIfSharepointS2SConfigurationEnabledRule

			// EntityPropertyRule - IsBusinessProcessEnabled
			#region EntityPropertyRule - IsBusinessProcessEnabled
			AddOptionValue("EntityPropertyRule", "PropertyName", "IsBusinessProcessEnabled");
			#endregion EntityPropertyRule - IsBusinessProcessEnabled

			// DeviceTypeRule
			#region DeviceTypeRule
			RemoveElement("DeviceTypeRule");
			#endregion DeviceTypeRule
		}

		public static void SwitchToVersion7()
		{
			// Load version 6.x support
			SwitchToVersion6();

			// Support for version 7.x Metadata elements

			// DeviceTypeRule
			#region DeviceTypeRule
			// NOTE: This rule is marked 'for internal use only'
			// SDK documentation says it exists starting from version 2015
			// SDK Ribbon schema files have this item only starting from version 2016
			if (!_cachedTypes.ContainsKey("DeviceTypeRule"))
			{
				_cachedTypes.Add("DeviceTypeRule", new ElementType()
				{
					ElementName = "DeviceTypeRule",
					TextFormat = "Device Type {=} {Type}",
					Description = "A rule that detects the type of Microsoft Dynamics CRM device (For internal use only)",
					Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Type", IsRequired = true, OptionValues = new string[] { "None", "Phone", "Tablet", "Web", "Outlook", "InteractionCentric" }},
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
				});
			}
			AddChildElement("DisplayRule", "DeviceTypeRule");
			AddChildElement("Or", "DeviceTypeRule"); // TODO: Separate Display and Enable Or Rules
			#endregion DeviceTypeRule
		}

		public static void SwitchToVersion8()
		{
			// Load version 7.x support
			SwitchToVersion7();

			// Support for version 8.x Metadata elements

			// FormTypeRule
			#region FormTypeRule
			AddOptionValue("FormTypeRule", "Type", "Card");
			AddOptionValue("FormTypeRule", "Type", "MainInteractionCentric");
			#endregion FormTypeRule

			// HideIfExportToExcelNotEnabledRule
			#region HideIfExportToExcelNotEnabledRule
			if (!_cachedTypes.ContainsKey("HideIfExportToExcelNotEnabledRule"))
			{
				_cachedTypes.Add("HideIfExportToExcelNotEnabledRule", new ElementType()
				{
					ElementName = "HideIfExportToExcelNotEnabledRule",
					TextFormat = "HideIfExportToExcelNotEnabledRule",
					Description = "For internal use only",
					Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
				});
				AddChildElement("DisplayRule", "HideIfExportToExcelNotEnabledRule");
				AddChildElement("EnableRule", "HideIfExportToExcelNotEnabledRule");
				AddChildElement("Or", "HideIfExportToExcelNotEnabledRule"); // TODO: Separate Display and Enable Or Rules
			}
			#endregion HideIfExportToExcelNotEnabledRule

			// IsExportToExcelOnlineEnabledRule
			#region IsExportToExcelOnlineEnabledRule
			if (!_cachedTypes.ContainsKey("IsExportToExcelOnlineEnabledRule"))
			{
				_cachedTypes.Add("IsExportToExcelOnlineEnabledRule", new ElementType()
				{
					ElementName = "IsExportToExcelOnlineEnabledRule",
					TextFormat = "IsExportToExcelOnlineEnabledRule",
					Description = "For internal use only",
					Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
				});
			}
			#endregion IsExportToExcelOnlineEnabledRule

			// HideIfDisabledForMobileRule
			#region HideIfDisabledForMobileRule
			if (!_cachedTypes.ContainsKey("HideIfDisabledForMobileRule"))
			{
				_cachedTypes.Add("HideIfDisabledForMobileRule", new ElementType()
				{
					ElementName = "HideIfDisabledForMobileRule",
					TextFormat = "HideIfDisabledForMobileRule",
					Description = "For internal use only",
					Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
				});
			}
			#endregion HideIfDisabledForMobileRule

			// HideIfHybridSSSNotEnabledRule
			#region HideIfHybridSSSNotEnabledRule
			if (!_cachedTypes.ContainsKey("HideIfHybridSSSNotEnabledRule"))
			{
				_cachedTypes.Add("HideIfHybridSSSNotEnabledRule", new ElementType()
				{
					ElementName = "HideIfHybridSSSNotEnabledRule",
					TextFormat = "HideIfHybridSSSNotEnabledRule",
					Description = "For internal use only",
					Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
				});
			}
			#endregion HideIfHybridSSSNotEnabledRule

			// HideIfDelveNotAvailableRule
			#region HideIfDelveNotAvailableRule
			if (!_cachedTypes.ContainsKey("HideIfDelveNotAvailableRule"))
			{
				_cachedTypes.Add("HideIfDelveNotAvailableRule", new ElementType()
				{
					ElementName = "HideIfDelveNotAvailableRule",
					TextFormat = "HideIfDelveNotAvailableRule",
					Description = "For internal use only",
					Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
				});
			}
			#endregion HideIfDelveNotAvailableRule

			// HideIfTestExchangeServerNotEnabledRule
			#region HideIfTestExchangeServerNotEnabledRule
			if (!_cachedTypes.ContainsKey("HideIfTestExchangeServerNotEnabledRule"))
			{
				_cachedTypes.Add("HideIfTestExchangeServerNotEnabledRule", new ElementType()
				{
					ElementName = "HideIfTestExchangeServerNotEnabledRule",
					TextFormat = "HideIfTestExchangeServerNotEnabledRule",
					Description = "For internal use only",
					Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
				});
			}
			#endregion HideIfTestExchangeServerNotEnabledRule

			// HideIfSSSTroubleshootingNotEnabledRule
			#region HideIfSSSTroubleshootingNotEnabledRule
			if (!_cachedTypes.ContainsKey("HideIfSSSTroubleshootingNotEnabledRule"))
			{
				_cachedTypes.Add("HideIfSSSTroubleshootingNotEnabledRule", new ElementType()
				{
					ElementName = "HideIfSSSTroubleshootingNotEnabledRule",
					TextFormat = "HideIfSSSTroubleshootingNotEnabledRule",
					Description = "For internal use only",
					Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
				});
			}
			#endregion HideIfSSSTroubleshootingNotEnabledRule

			// HideIfCurrentUserIsNotSystemAdministratorRule
			#region HideIfCurrentUserIsNotSystemAdministratorRule
			if (!_cachedTypes.ContainsKey("HideIfCurrentUserIsNotSystemAdministratorRule"))
			{
				_cachedTypes.Add("HideIfCurrentUserIsNotSystemAdministratorRule", new ElementType()
				{
					ElementName = "HideIfCurrentUserIsNotSystemAdministratorRule",
					TextFormat = "HideIfCurrentUserIsNotSystemAdministratorRule",
					Description = "For internal use only",
					Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
				});
			}
			#endregion HideIfCurrentUserIsNotSystemAdministratorRule

			// FeatureControlRule
			#region FeatureControlRule
			if (!_cachedTypes.ContainsKey("FeatureControlRule"))
			{
				_cachedTypes.Add("FeatureControlRule", new ElementType()
				{
					ElementName = "FeatureControlRule",
					TextFormat = "FeatureControlRule",
					Description = "For internal use only",
					Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "FeatureControlBit", FreeText = true, IsRequired = true },
					new AttributeType(){ AttributeName = "ExpectedValue", IsRequired = true, OptionValues = new string[] { "true", "false" } },
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" } }
				}
				});
			}
			#endregion FeatureControlRule

			// HideIfEmailSignatureNotEnabledRule
			#region HideIfEmailSignatureNotEnabledRule
			if (!_cachedTypes.ContainsKey("HideIfEmailSignatureNotEnabledRule"))
			{
				_cachedTypes.Add("HideIfEmailSignatureNotEnabledRule", new ElementType()
				{
					ElementName = "HideIfEmailSignatureNotEnabledRule",
					TextFormat = "HideIfEmailSignatureNotEnabledRule",
					Description = "For internal use only (undocumented)",
					Attributes = new AttributeType[]
				{
					new AttributeType(){ AttributeName = "Default", OptionValues = new string[] { "true", "false" }},
					new AttributeType(){ AttributeName = "InvertResult", OptionValues = new string[] { "true", "false" }}
				}
				});
			}
			#endregion HideIfEmailSignatureNotEnabledRule
		}

		private static void RemoveElement(string ElementName)
		{
			if (_cachedTypes.ContainsKey(ElementName))
			{
				_cachedTypes.Remove(ElementName);
			}
		}
		private static void AddChildElement(string ElementName, string ChildElementName)
		{
			if (_cachedTypes.ContainsKey(ElementName))
			{
				List<string> elements = new List<string>(_cachedTypes[ElementName].ChildElements);
				if (!elements.Contains(ChildElementName))
				{
					elements.Add(ChildElementName);
					elements.Sort();
					_cachedTypes[ElementName].ChildElements = elements.ToArray();
				}
			}
		}
		private static void RemoveChildElement(string ElementName, string ChildElementName)
		{
			if (_cachedTypes.ContainsKey(ElementName))
			{
				List<string> elements = new List<string>(_cachedTypes[ElementName].ChildElements);
				if (elements.Contains(ChildElementName))
				{
					elements.Remove(ChildElementName);
					_cachedTypes[ElementName].ChildElements = elements.ToArray();
				}
			}
		}
		private static void AddOptionValue(string ElementName, string AttributeName, string OptionValue)
		{
			if (_cachedTypes.ContainsKey(ElementName))
			{
				List<AttributeType> attributes = new List<AttributeType>(_cachedTypes[ElementName].Attributes);
				foreach (AttributeType attribute in attributes)
				{
					if (attribute.AttributeName == AttributeName)
					{
						List<string> optionValues = new List<string>(attribute.OptionValues);
						if (!optionValues.Contains(OptionValue))
						{
							optionValues.Add(OptionValue);
							attribute.OptionValues = optionValues.ToArray();
							_cachedTypes[ElementName].Attributes = attributes.ToArray();
							return;
						}
					}
				}
			}
		}
		private static void RemoveOptionValue(string ElementName, string AttributeName, string OptionValue)
		{
			if (_cachedTypes.ContainsKey(ElementName))
			{
				List<AttributeType> attributes = new List<AttributeType>(_cachedTypes[ElementName].Attributes);
				foreach (AttributeType attribute in attributes)
				{
					if (attribute.AttributeName == AttributeName)
					{
						List<string> optionValues = new List<string>(attribute.OptionValues);
						if (optionValues.Contains(OptionValue))
						{
							optionValues.Remove(OptionValue);
							attribute.OptionValues = optionValues.ToArray();
							_cachedTypes[ElementName].Attributes = attributes.ToArray();
							return;
						}
					}
				}
			}
		}
	}
}